package cn.piesat.scanning.business.dq1043.flow;

import cn.piesat.scanning.service.*;
import com.alibaba.fastjson.JSON;
import cn.piesat.scanning.business.common.algorithm.processAlgorithm.FlowAlgorithmParam;
import cn.piesat.scanning.business.common.algorithm.processAlgorithm.FlowTaskAbstract;
import cn.piesat.scanning.business.dq1043.vo.RuleVO;
import cn.piesat.scanning.dto.DbDmsScanningMetadataAuxInfoDTO;
import cn.piesat.scanning.dto.HtPathConfigurationDTO;
import cn.piesat.scanning.dto.HtScanningMetadataDTO;
import cn.piesat.scanning.dto.HtScheduleJobDTO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.sql.Date;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xhl
 */
@Component
public class FlowTask extends FlowTaskAbstract {

    private final DateTimeFormatter TIME_FORMAT =  DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final Logger logger = LoggerFactory.getLogger(FlowTask.class);
    @Value("${scanning.data.day}")
    private Integer nearDay;
    @Autowired
    private HtScanningMetadataService htScanningMetadataService;
    @Autowired
    private DbDmsSchedulerTaskFileRecordService dbDmsSchedulerTaskFileRecordService;
    @Autowired
    private HtPathConfigurationService htPathConfigurationService;
    @Autowired
    private FlowAlgorithmParamsService flowAlgorithmParamsService;
    @Autowired
    private DbDmsScanningMetadataAuxInfoService dbDmsScanningMetadataAuxInfoService;

    @Override
    public void parseRuleAndFindData(List<FlowAlgorithmParam> algorithmParams, HtScheduleJobDTO taskDTO) {
        //查找可执行的景号集合，默认使用配置的时间至最新的时间，如果为重做流程任务，则从任务信息中获取时间
        LocalDateTime now = LocalDateTime.now();
        String startTime = TIME_FORMAT.format(now.plusDays(-1L * nearDay));
        String endTime = TIME_FORMAT.format(now);
        if ("redo_flowTask".equals(taskDTO.getTaskType())){
            Date redoStartTime = taskDTO.getRedoStartTime();
            Date redoEndTime = taskDTO.getRedoEndTime();
            startTime = TIME_FORMAT.format(redoStartTime.toInstant().atZone(ZoneId.systemDefault()));
            endTime = TIME_FORMAT.format(redoEndTime.toInstant().atZone(ZoneId.systemDefault()));
        }
        List<String> allViewNumber = htScanningMetadataService.groupByViewNumber("L1%", startTime,endTime);
        //记录表中的FileName字段存储的为景号
        List<String> existViewNumber = dbDmsSchedulerTaskFileRecordService.findFileNameListByTaskId(taskDTO.getId());
        List<String> execViewNumberList = allViewNumber.stream()
                .filter(viewNumber -> !existViewNumber.contains(viewNumber))
                .collect(Collectors.toList());
        assembleData(algorithmParams, taskDTO, execViewNumberList,false,null);
    }



    /**
     * 根据规则组装数据信息
     * @param algorithmParams 算法参数集合
     * @param taskDTO   任务信息对象
     * @param execViewNumberList 可执行的景号集合
     * @param isRedo 是否为重做方式调用该方法
     * @param metadataList 主文件信息集合，只有在isRedo为true时才有用，为false传null即可
     */
    private void  assembleData(List<FlowAlgorithmParam> algorithmParams, HtScheduleJobDTO taskDTO,
                              List<String> execViewNumberList, boolean isRedo, List<HtScanningMetadataDTO> metadataList) {
        for (String viewNumber : execViewNumberList) {
            String taskPlanId = htScanningMetadataService.findByViewNumberDistinct(viewNumber);
            for (FlowAlgorithmParam flowAlgorithmParam : algorithmParams) {
                String algorithmId = flowAlgorithmParam.getAlgorithmId();
                Map<String, Object> flowInputParamMap = flowAlgorithmParam.getFlowInputParam();
                FlowInputParam flowInputParam = JSON.parseObject(JSON.toJSONString(flowInputParamMap), FlowInputParam.class);
                Map<String, Object> flowRuleParamMap = flowAlgorithmParam.getFlowRuleParam();
                FlowRuleParam flowRuleParam = JSON.parseObject(JSON.toJSONString(flowRuleParamMap), FlowRuleParam.class);
                if (StringUtils.isBlank(flowRuleParam.getPrimaryFile())) {
                    logger.info("波段数据规则为空");
                    return ;
                }
                RuleVO primaryFileRule = JSON.parseObject(flowRuleParam.getPrimaryFile(), RuleVO.class);
                HtPathConfigurationDTO pathDTO = htPathConfigurationService.findById(flowRuleParam.getPathConfigId());
                // "|"和，";"或，","模式区分，将所有该景号的通道或传感器文件找到放入内存，减少与数据库操作
                List<String> allBandOrSensorList = Arrays.stream(primaryFileRule.getMatchRule()
                        .split(",|;|\\|"))
                        .distinct()
                        .collect(Collectors.toList());
                RuleVO preProcessRule = JSON.parseObject(flowRuleParam.getPreprocess(),RuleVO.class);
                boolean preProcess = JSON.parseObject(preProcessRule.getMatchRule(),Boolean.class);
                List<HtScanningMetadataDTO> allPrimaryDataList = listAllPrimaryData(allBandOrSensorList,viewNumber,preProcess,primaryFileRule.getLevel());
                Map<String,List<HtScanningMetadataDTO>> hash = new HashMap<>();
                if (preProcess) {
                    allPrimaryDataList.forEach(dto -> {
                        List<HtScanningMetadataDTO> list = null;
                        if (hash.containsKey(dto.getSensor())){
                            list = hash.get(dto.getSensor());
                        } else {
                            list = new ArrayList<>();
                            hash.put(dto.getSensor(),list);
                        }
                        list.add(dto);
                    });
                } else {
                    allPrimaryDataList.forEach(dto -> {
                        List<HtScanningMetadataDTO> list = null;
                        if (hash.containsKey(dto.getBands())){
                            list = hash.get(dto.getBands());
                        } else {
                            list = new ArrayList<>();
                            hash.put(dto.getBands(),list);
                        }
                        list.add(dto);
                    });
                }
                //解析主文件信息
                String[] allGroup = primaryFileRule.getMatchRule().split(";");
                List<FlowMessageParam> allSendMessage = new ArrayList<>();
                //TODO 暂时只满足1043 所有模式的主文件都相同（B12）
                //先根据B12查询到源数据集合，如果一个条件不满足，就走下一个模式
                //所有条件下都不满足时记录的日志标志
                boolean noExecLogFlag = false;
                for (String group : allGroup) {
                    String[] eachBand = group.split(",|\\|");
                    //主文件
                    List<HtScanningMetadataDTO> mainFileDataList = null;
                    if (isRedo) {
                        mainFileDataList = metadataList;
                    } else {
                        mainFileDataList = hash.get(eachBand[0]);
                    }
                    if (mainFileDataList == null || mainFileDataList.isEmpty()) {
                        continue;
                    }
                    noExecLogFlag = true;
                    String[] allMode = group.split(",");
                    for (HtScanningMetadataDTO mainFileData : mainFileDataList) {
                        //单个文件重做的时候，需要判断传入的文件和当前的主文件通道或传感器是否一致
                        if (preProcess) {
                            String sensor = mainFileData.getSensor();
                            if (!sensor.equals(eachBand[0])) {
                                break;
                            }
                        } else {
                            String bands = mainFileData.getBands();
                            if (!bands.equals(eachBand[0])) {
                                break;
                            }
                        }
                        boolean execBool = true;
                        int count = 0;
                        String primaryFile = "";
                        for (String mode : allMode) {
                            primaryFile = primaryRule(mainFileData,pathDTO,primaryFileRule,preProcess,hash,mode);
                            if (primaryFile == null) {
                                count++;
                                if (count == allMode.length) {
                                    //组装无法执行状态消息，主文件存在，但是其他通道的文件不存在的情况
                                    createStateMessage(allSendMessage, mainFileData,mainFileData.getFileName() + "所有模式都不满足通道数据规则");
                                    execBool = false;
                                }
                            } else {
                                break;
                            }
                        }
                        if (execBool) {
                            Map<String,String> geoMap = geoFileRule(mainFileData,flowRuleParam,preProcess,flowInputParam.getGeoFile());
                            if (geoMap == null) {
                                createStateMessage(allSendMessage, mainFileData,mainFileData.getFileName() + "缺少GEO或RPC文件");
                                continue;
                            }
                            String l2File = l2Rule(mainFileData,flowRuleParam.getL2File(),flowInputParam.getL2File());
                            if (l2File == null) {
                                //组装无法执行状态消息，L2文件不存在
                                createStateMessage(allSendMessage, mainFileData,mainFileData.getFileName() + "缺少L2级产品文件");
                                continue;
                            }
                            String nwpFile = nwpRule(flowRuleParam.getNwpFile(),mainFileData.getFileDate(),flowInputParam.getNwpFile());
                            if (nwpFile == null) {
                                //组装无法执行状态消息，T799数据不存在
                                createStateMessage(allSendMessage, mainFileData,mainFileData.getFileName() + "缺少T799数值预报数据");
                                continue;
                            }
                            //组装待执行状态信息，查找到文件及路径
                            FlowMessageParam message = new FlowMessageParam();
                            Map<String,Object> algorithmParam = new HashMap<>();
                            algorithmParam.put("primaryFile",primaryFile);
                            algorithmParam.put("geoFile",geoMap.get("geo"));
                            algorithmParam.put("L2File",l2File);
                            algorithmParam.put("nwpFile",nwpFile);
                            algorithmParam.put("rpbFile",geoMap.get("rpc"));
                            algorithmParam.put("tcfPath",flowInputParam.getTcfPath());
                            algorithmParam.put("resultPath",pathDTO.getOutputPath());
                            algorithmParam.put("auxPath",pathDTO.getAssistPath());
                            algorithmParam.put("mainFileName",mainFileData.getFileName());
                            Map<String,Object> map = new HashMap<>();
                            map.put("preprocess",preProcess);
                            map.put("algorithmId",algorithmId);
                            map.put("pathConfigId",pathDTO.getId());
                            map.put("viewNumber",mainFileData.getViewNumber());
                            map.put("fileDate",mainFileData.getFileDate());
                            map.put("taskPlanId",mainFileData.getTaskPlanId());
                            map.put("lon",mainFileData.getLon());
                            map.put("lat",mainFileData.getLat());
                            message.setStatus(0);
                            message.setMainFileData(mainFileData);
                            message.setExecParam(map);
                            message.setAlgorithmParam(algorithmParam);
                            allSendMessage.add(message);
                        }

                    }
                }
                if (!noExecLogFlag) {
                    createStateMessage(allSendMessage, null,"无可执行的文件");
                }
                //修改所有的信息记录并发送Kafka消息
                updateRecordAndSendMessage(taskPlanId,viewNumber,taskDTO,allSendMessage,algorithmId);
            }
        }
    }

    @Override
    public void parseRuleAndFindData(List<FlowAlgorithmParam> algorithmParams, HtScheduleJobDTO taskDTO, List<String> dataList) {
        assembleData(algorithmParams,taskDTO,dataList,false,null);
    }

    @Override
    public void singleFileRedo(String algorithmId, HtScheduleJobDTO taskDTO, HtScanningMetadataDTO metadataDTO) {
        List<HtScanningMetadataDTO> metadataList = new ArrayList<>();
        metadataList.add(metadataDTO);
        List<String> execViweNumberList = new ArrayList<>();
        execViweNumberList.add(metadataDTO.getViewNumber());
        List<FlowAlgorithmParam> algorithmParams = new ArrayList<>();
        FlowAlgorithmParam params = new FlowAlgorithmParam();
        Map<String, Object> inputParam = flowAlgorithmParamsService.findDynamicParams(taskDTO.getFlowId(), algorithmId);
        Map<String, Object> ruleParam = flowAlgorithmParamsService.findFixedParams(taskDTO.getFlowId(), algorithmId);
        params.setAlgorithmId(algorithmId);
        params.setFlowInputParam(inputParam);
        params.setFlowRuleParam(ruleParam);
        algorithmParams.add(params);
        assembleData(algorithmParams,taskDTO,execViweNumberList,true,metadataList);
    }

    private String nwpRule(String nwpFile, String mainFileDate, String npwPathPrefix) {
        StringBuilder filePathSb = new StringBuilder();
        if (StringUtils.isBlank(nwpFile)) {
            return filePathSb.toString();
        }
        RuleVO nwpRuleVO = JSON.parseObject(nwpFile, RuleVO.class);
        if ("NULL".equals(nwpRuleVO.getMatchRule()) || "NULL".equals(nwpRuleVO.getLevel())) {
            return filePathSb.toString();
        }
        //将主文件时间转为世界时来匹配数值预报数据
        mainFileDate = TIME_FORMAT.format(LocalDateTime.parse(mainFileDate, TIME_FORMAT).plusHours(-8L));
        //查询48小时内在数据库种条件要素的文件是否存在，并且数量至少为3个。
        long earlyHour = (-1) * 48L;
        String earlyTime = TIME_FORMAT.format(LocalDateTime.parse(mainFileDate, TIME_FORMAT).plusHours(earlyHour));
        String[] mathexpArr = nwpRuleVO.getMatchRule().split("\\|");
        List<DbDmsScanningMetadataAuxInfoDTO> earlyAllData = dbDmsScanningMetadataAuxInfoService.
                listByFileWantListAndRangeTimeOrder(Arrays.asList(mathexpArr), earlyTime, mainFileDate);
        Map<String, Long> countAllNwpMap = earlyAllData.stream()
                .collect(Collectors.groupingBy(DbDmsScanningMetadataAuxInfoDTO::getFileWant, Collectors.counting()));
        if (mathexpArr.length != countAllNwpMap.size()) {
            return null;
        }
        for (Map.Entry<String, Long> entry : countAllNwpMap.entrySet()) {
            if (entry.getValue() < 3) {
                return null;
            }
        }
        //过滤筛筛选出符合规则要求的时次的要素文件  每种要素3个数据信息
        Map<String, String> timeRange = parseTimeRange(nwpRuleVO.getTimeRange(), mainFileDate);
        LocalDateTime nwpStartTime = LocalDateTime.parse(timeRange.get("startTime"), TIME_FORMAT);
        LocalDateTime nwpEndTime = LocalDateTime.parse(timeRange.get("endTime"), TIME_FORMAT);
        //key:要素 value:[nwp数据（时间+时次会重复）]
        Map<String, List<DbDmsScanningMetadataAuxInfoDTO>> filterMap = earlyAllData.stream().filter(dto -> {
            LocalDateTime dtoLocalDateTime = LocalDateTime.parse(dto.getFileDate(), TIME_FORMAT).plusHours(dto.getFileTimeSecond());
            return !nwpStartTime.isAfter(dtoLocalDateTime) && !nwpEndTime.isBefore(dtoLocalDateTime);
        }).collect(Collectors.groupingBy(DbDmsScanningMetadataAuxInfoDTO::getFileWant));
        for (Map.Entry<String,List<DbDmsScanningMetadataAuxInfoDTO>> entry : filterMap.entrySet()) {
            List<DbDmsScanningMetadataAuxInfoDTO> wantList = entry.getValue();
            List<DbDmsScanningMetadataAuxInfoDTO> nwpInfoList = new ArrayList<>();
            Map<String,DbDmsScanningMetadataAuxInfoDTO> hash = new HashMap<>();
            for (DbDmsScanningMetadataAuxInfoDTO nwpDTO : wantList) {
                String formatDate = TIME_FORMAT.format(LocalDateTime.parse(nwpDTO.getFileDate(),TIME_FORMAT).plusHours(nwpDTO.getFileTimeSecond()));
                if (!hash.containsKey(formatDate)) {
                    hash.put(formatDate,nwpDTO);
                    nwpInfoList.add(nwpDTO);
                }
            }
            if (nwpInfoList.size() < 3) {
                return null;
            }
            //查找最接近的三个数量文件
            List<Long> nearPrimaryFileTime = findNearDateNwpFile(nwpInfoList,mainFileDate);
            //判断磁盘上是否存在
            for (Long keyMilli : nearPrimaryFileTime) {
                String keyTime = TIME_FORMAT.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(keyMilli),ZoneId.systemDefault()));
                DbDmsScanningMetadataAuxInfoDTO currentFileDTO = hash.get(keyTime);
                String currentPath = npwPathPrefix + File.separator + currentFileDTO.getFilePath();
                File file = new File(currentPath);
                if (!file.exists()) {
                    return null;
                }
                filePathSb.append(",").append(currentPath);
            }
        }
        return filePathSb.substring(1);
    }

    private List<Long> findNearDateNwpFile(List<DbDmsScanningMetadataAuxInfoDTO> nwpInfoList, String mainFileDate) {
        long primaryFileMilli = LocalDateTime.parse(mainFileDate,TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        List<Long> nearPrimaryFileTime = new ArrayList<>();
        for (int j = 0; j < nwpInfoList.size(); j++) {
            DbDmsScanningMetadataAuxInfoDTO metadataAuxInfoDTO = nwpInfoList.get(j);
            long currentFileMilli = LocalDateTime.parse(metadataAuxInfoDTO.getFileDate(),TIME_FORMAT).plusHours(metadataAuxInfoDTO.getFileTimeSecond()).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            if (j < 3) {
                nearPrimaryFileTime.add(currentFileMilli);
            } else {
                //主文件时次右边是从大到小遍历，所以直接替换，保持最右是最小最近的文件时间，最左边是最大的。
                if (currentFileMilli - primaryFileMilli >= 0) {
                    nearPrimaryFileTime.remove(0);
                    nearPrimaryFileTime.add(currentFileMilli);
                } else {
                    //左边进行比较
                    long dif = primaryFileMilli - currentFileMilli;
                    long max = nearPrimaryFileTime.stream().max((a,b) -> Math.abs(a - primaryFileMilli) > Math.abs(b - primaryFileMilli) ? 1 : -1).get();
                    if (dif < Math.abs(max - primaryFileMilli)) {
                        nearPrimaryFileTime.remove(max);
                        nearPrimaryFileTime.add(currentFileMilli);
                    } else {
                        break;
                    }
                }
            }
        }
        return nearPrimaryFileTime;
    }
    private String l2Rule(HtScanningMetadataDTO mainFileData, String l2RuleStr, String l2InputPath) {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isBlank(l2RuleStr)) {
            return sb.toString();
        }
        RuleVO ruleVO = JSON.parseObject(l2RuleStr, RuleVO.class);
        if ("NULL".equals(ruleVO.getMatchRule()) || "NULL".equals(ruleVO.getLevel())) {
            return sb.toString();
        }
        Map<String, String> timeRange = parseTimeRange(ruleVO.getTimeRange(),mainFileData.getFileDate());
        String startTime = timeRange.get("startTime");
        String endTime = timeRange.get("endTime");
        String[] productGroup = ruleVO.getMatchRule().split("\\|");
        List<HtScanningMetadataDTO> ruleFileList = new ArrayList<>();
        if (startTime.equals(endTime)) {
            startTime = TIME_FORMAT.format(LocalDateTime.parse(mainFileData.getFileDate(),TIME_FORMAT).plusMinutes(-1 * 3));
            endTime = TIME_FORMAT.format(LocalDateTime.parse(mainFileData.getFileDate(),TIME_FORMAT).plusMinutes(3));
            List<HtScanningMetadataDTO> dataList = htScanningMetadataService
                    .listByProductIidListAndTimeRangeAndLevel(Arrays.asList(productGroup), startTime,endTime,ruleVO.getLevel());
            double lon = Double.parseDouble(mainFileData.getLon().substring(1));
            double lat = Double.parseDouble(mainFileData.getLat().substring(1));
            ruleFileList.addAll(dataList.stream().filter(dto -> {
                double dLon = Double.parseDouble(dto.getLon().substring(1));
                double dLat = Double.parseDouble(dto.getLat().substring(1));
                return dLon >= lon - 0.5 && dLon <= lon + 0.5 && dLat >= lat - 0.5 && dLat <= lat + 0.5;
            }).collect(Collectors.toList()));
        } else {
            //TODO 需要多批L2数据的情况逻辑，暂无

        }
        Map<String, List<HtScanningMetadataDTO>> filterMap = ruleFileList.stream()
                .collect(Collectors.groupingBy(HtScanningMetadataDTO::getProductIid));
        if (filterMap.size() != productGroup.length) {
            return null;
        }
        if (startTime.equals(endTime)) {
            //筛选最接近主文件时次的产品文件
            List<HtScanningMetadataDTO> tempList = new ArrayList<>();
            long mainFileMilli = LocalDateTime.parse(mainFileData.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            filterMap.values().forEach(list -> {
                HtScanningMetadataDTO resultDTO = list.stream().min((a, b) -> {
                    long aMilli = LocalDateTime.parse(a.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                    long bMilli = LocalDateTime.parse(b.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                    return Math.abs(aMilli - mainFileMilli) > Math.abs(bMilli - mainFileMilli) ? 1 : -1;
                }).get();
                tempList.add(resultDTO);
            });
            ruleFileList = tempList;
        }
        for (HtScanningMetadataDTO fileDTO : ruleFileList) {
            String currentPath = l2InputPath + File.separator + fileDTO.getFilePath();
            File file = new File(currentPath);
            if (!file.exists()) {
                return null;
            }
            sb.append(",").append(currentPath);
        }
        return sb.substring(1);
    }

    private void createStateMessage(List<FlowMessageParam> allSendMessage, HtScanningMetadataDTO mainFileData, String log) {
        FlowMessageParam message = new FlowMessageParam();
        Map<String, Object> map = new HashMap<>();
        map.put("log", log);
        message.setMainFileData(mainFileData);
        message.setStatus(-1);
        message.setExecParam(map);
        allSendMessage.add(message);
    }

    private Map<String,String> geoFileRule(HtScanningMetadataDTO mainFileData, FlowRuleParam ruleParam, boolean preProcess, String geoInputPath) {
        StringBuilder geoSb = new StringBuilder();
        StringBuilder rpcSb = new StringBuilder();
        Map<String,String> resultMap = new HashMap<>();
        String geoRuleStr = ruleParam.getGeoFile();
        if (StringUtils.isBlank(geoRuleStr)) {
            resultMap.put("geo",geoSb.toString());
            resultMap.put("rpc",rpcSb.toString());
            return resultMap;
        }
        RuleVO geoRule = JSON.parseObject(geoRuleStr, RuleVO.class);
        if ("NULL".equals(geoRule.getMatchRule()) || "NULL".equals(geoRule.getLevel())) {
            resultMap.put("geo",geoSb.toString());
            resultMap.put("rpc",rpcSb.toString());
            return resultMap;
        }
        Map<String, String> timeRange = parseTimeRange(geoRule.getTimeRange(), mainFileData.getFileDate());
        String startTime = timeRange.get("startTime");
        String endTime = timeRange.get("endTime");
        List<HtScanningMetadataDTO> geoDataList = null;
        if (preProcess) {
            //标准化处理所需要的GEO、RPC文件扫描规则，当前的扫描逻辑只能暂时支持流程方式配置多种标准化处理，标准化处理中primary不包括备用模式，不会出现","
            String mainSensor = mainFileData.getSensor();
            String viewNumber = mainFileData.getViewNumber();
            geoDataList = htScanningMetadataService
                    .listBySensorAndViewNumberAndLevelAndTimeRange(mainSensor, viewNumber, geoRule.getLevel(),startTime,endTime);
            //流程中的配置格式：例：primary（VNIR;TIR;MIR） 对应的GEO应为（GEO|01|02|03|04；01|02|03；07|08|09）
            RuleVO primaryRule = JSON.parseObject(ruleParam.getPrimaryFile(), RuleVO.class);
            String primary = primaryRule.getMatchRule();
            String geo = geoRule.getMatchRule();
            String[] primaryGroup = primary.split(";");
            String[] geoGroup = geo.split(";");
            if (primaryGroup.length != geoGroup.length) {
                return null;
            }
            String mainGeoMatch = "";
            for (int i = 0 ; i < primaryGroup.length ; i++) {
                if (mainSensor.equals(primaryGroup[i])) {
                    mainGeoMatch = geoGroup[i];
                    break;
                }
            }
            Set<String> geoHashSet = new HashSet<>(Arrays.asList(mainGeoMatch.split("\\|")));
            geoDataList = geoDataList.stream()
                    .filter(dto -> {
                        String[] nameGroup = dto.getFileName().split("_");
                        return geoHashSet.contains(nameGroup[nameGroup.length - 2]);
                    }).collect(Collectors.toList());
            if (geoDataList.size() != geoHashSet.size()) {
                return null;
            }
            if (geoDataList.isEmpty()) {
                return null;
            }
            //判断磁盘上文件是否存在
            for (HtScanningMetadataDTO fileDTO : geoDataList) {
                String currentFilePath = geoInputPath + File.separator + fileDTO.getFilePath();
                File file = new File(currentFilePath);
                if (!file.exists()) {
                    return null;
                }
                if ("HDF".equals(fileDTO.getFileType())) {
                    geoSb.append(",").append(currentFilePath);
                } else if ("RPB".equals(fileDTO.getFileType())) {
                    rpcSb.append(",").append(currentFilePath);
                }
            }
        } else {
            //TODO 专业处理算法需要的GEO扫描规则
        }
        resultMap.put("geo",geoSb.toString().contains(",") ? geoSb.substring(1) : geoSb.toString());
        resultMap.put("rpc",rpcSb.toString().contains(",") ? rpcSb.substring(1) : rpcSb.toString());
        return resultMap;
    }

    private List<HtScanningMetadataDTO> listAllPrimaryData(List<String> allBandOrSensorList, String viewNumber,
                                                           boolean preProcess, String level) {
        List<HtScanningMetadataDTO> list = null;
        if (preProcess) {
            list = htScanningMetadataService.listBySensorListAndViewNumberAndLevel(allBandOrSensorList,viewNumber,level);
        } else {
            list = htScanningMetadataService.listByBandListAndViewNumberAndLevel(allBandOrSensorList,viewNumber,level);
        }
        return list;
    }

    private String primaryRule(HtScanningMetadataDTO mainFileData, HtPathConfigurationDTO pathDTO,
                               RuleVO primaryFileRule, boolean preProcess, Map<String,List<HtScanningMetadataDTO>> hash,
                               String mode) {
        if (preProcess) {
            String path = mainFileData.getFilePath();
            File file = new File(pathDTO.getScanningPath() + File.separator + path);
            if (file.exists()) {
                return pathDTO.getClientPath() + File.separator + path;
            } else {
                return null;
            }
        } else {
            String timeRangeStr = primaryFileRule.getTimeRange();
            Map<String, String> timeRange = parseTimeRange(timeRangeStr,mainFileData.getFileDate());
            String startTime = timeRange.get("startTime");
            String endTime = timeRange.get("endTime");
            if (startTime.equals(endTime)) {
                return findPrimaryFile(hash,pathDTO,mode,mainFileData);
            } else {
                List<HtScanningMetadataDTO> sameBandDataList = hash.get(mainFileData.getBands());
                long startMilli = LocalDateTime.parse(startTime,TIME_FORMAT)
                        .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                long endMilli = LocalDateTime.parse(endTime,TIME_FORMAT)
                        .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                List<HtScanningMetadataDTO> dataList = sameBandDataList.stream()
                        .filter(dto -> {
                            long currentMilli = LocalDateTime.parse(dto.getFileDate(), TIME_FORMAT)
                                    .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                            return startMilli <= currentMilli && currentMilli <= endMilli;
                        }).collect(Collectors.toList());
                StringBuilder sb = new StringBuilder();
                for (HtScanningMetadataDTO metadataDTO : dataList) {
                    String reAppendPath = findPrimaryFile(hash,pathDTO,mode,metadataDTO);
                    if (reAppendPath == null) {
                        return null;
                    }
                    sb.append(";").append(reAppendPath);
                }
                return sb.substring(1);
            }
        }
    }

    private String findPrimaryFile(Map<String, List<HtScanningMetadataDTO>> hash, HtPathConfigurationDTO pathDTO,
                                 String mode, HtScanningMetadataDTO mainFileData) {
        String[] allBand = mode.split("\\|");
        List<String> filePathList = new ArrayList<>();
        filePathList.add(mainFileData.getFilePath());
        for (int i = 1 ; i < allBand.length ; i++) {
            String band = allBand[i];
            List<HtScanningMetadataDTO> dataList = hash.get(band);
            if (dataList == null || dataList.isEmpty()) {
                return null;
            }
            //过滤和主文件时次最接近的文件
            long mainFileMilli = LocalDateTime.parse(mainFileData.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            HtScanningMetadataDTO htScanningMetadataDTO = dataList.stream()
                    .min((a, b) -> {
                        long aMilli = LocalDateTime.parse(a.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                        long bMilli = LocalDateTime.parse(b.getFileDate(), TIME_FORMAT).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                        return Math.abs(aMilli - mainFileMilli) > Math.abs(bMilli - mainFileMilli) ? 1 : -1;
                    }).get();
            filePathList.add(htScanningMetadataDTO.getFilePath());
        }
        StringBuilder sb = new StringBuilder();
        for (String path : filePathList) {
            File file = new File(pathDTO.getScanningPath() + File.separator + path);
            if (!file.exists()) {
                return null;
            }
            sb.append(",").append(pathDTO.getClientPath()).append(File.separator).append(path);
        }
        return sb.substring(1);
    }



    private Map<String,String> parseTimeRange(String timeRange, String mainFileDate) {
        Map<String,String> resultMap = new HashMap<>();
        resultMap.put("startTime",mainFileDate);
        resultMap.put("endTime",mainFileDate);
        if (timeRange.equals("NULL")) {
            return resultMap;
        }
        String[] timeSplit = timeRange.split(",");
        long startPlusMinute = -1 * Math.abs(Long.parseLong(timeSplit[0]));
        long endPlusMinute = Math.abs(Long.parseLong(timeSplit[1]));
        LocalDateTime mainFileLocalDateTime = LocalDateTime.parse(mainFileDate, TIME_FORMAT);
        String startTime = TIME_FORMAT.format(mainFileLocalDateTime.plusMinutes(startPlusMinute));
        String endTime = TIME_FORMAT.format(mainFileLocalDateTime.plusMinutes(endPlusMinute));
        resultMap.put("startTime",startTime);
        resultMap.put("endTime",endTime);
        return resultMap;
    }




}
